/*	TMModelKeyFromViewNameTransformer.m
 *
 * Copyright (c)2005 Tim Morgan. All rights reserved. Please visit
 * http://tmorgan.shutupgeorge.com/other/license.html for more information about
 * your rights and responsibilities regarding this source code.
 */

#import "TMModelKeyFromViewNameTransformer.h"

@interface TMModelKeyFromViewNameTransformer (Invoked)

/**
 * Returns <code>NSString</code>, since this class ostensibly only translates
 * keys and names encoded as string objects. However, this class can in
 * actuality map any object type to any other object type, so long as the
 * Nib is prepared to handle it.
 *
 * @return <code>NSString</code> class
 */

+ (Class) transformedValueClass;

/**
 * Returns YES unconditionally.
 *
 * @return YES
 */

+ (BOOL) allowsReverseTransformation;

/**
 * Given a model key, returns the associated view name. Returns nil when given
 * nil or when the given key does not exist.
 *
 * @param value the model key
 * @return The associated view name, or nil for an unknown key
 */

- (id) transformedValue:(id)value;

/**
 * Given a view name, returns the associated model key. Returns nil when given
 * nil or when the given name does not exist.
 *
 * @param value the view name
 * @return The associated model key, or nil for an unknown name
 */

- (id) reverseTransformedValue:(id)value;

@end

@implementation TMModelKeyFromViewNameTransformer

#pragma mark <<initialization/deallocation>>

- (id) init {
	if (self = [super init]) {
		namesForKeys = [[NSMutableDictionary alloc] initWithCapacity:5];
		keysForNames = [[NSMutableDictionary alloc] initWithCapacity:5];
	}
	return self;
}

- (id) initWithMappingPlist:(NSString *)plistFile {
	if (self = [self init]) {
		NSString *errorStr;
		NSError *error;
		NSPropertyListFormat format;
		
		NSData *plistData = [NSData dataWithContentsOfFile:plistFile options:0 error:&error];
		if (!plistData) {
			NSLog([error localizedDescription]);
			[[NSException exceptionWithName:@"TMFileNotFoundException"
									 reason:@"A property list file was not found."
								   userInfo:nil] raise];
		}
		
		id plist = [NSPropertyListSerialization propertyListFromData:plistData
													mutabilityOption:NSPropertyListImmutable
															  format:&format
													errorDescription:&errorStr];
		if (!plist) {
			NSLog(errorStr);
			[[NSException exceptionWithName:@"TMIncorrectlyFormattedFileException"
									 reason:@"A property list file is not properly formatted."
								   userInfo:nil] raise];
		}
		if (![plist isKindOfClass:[NSDictionary class]])
			[[NSException exceptionWithName:@"TMUnexpectedDataTypeException"
									 reason:@"A property list file is not properly formatted."
								   userInfo:nil] raise];
	
		NSEnumerator *keys = [plist keyEnumerator];
		// note that the plist file has the view NAME as the plist KEY and the model KEY as the plist VALUE
		id key;
		while (key = [keys nextObject]) [self associateViewName:key withModelKey:[plist valueForKey:key]];
	}
	return self;
}

- (void) dealloc {
	[namesForKeys release];
	[keysForNames release];
	
	[super dealloc];
}

#pragma mark <<association>>

- (void) associateViewName:(id)name withModelKey:(id)key {
	if (name == nil || key == nil) return;
	
	NSString *keyString;
	if (![name isKindOfClass:[NSString class]])
		[[NSException exceptionWithName:@"TMInvalidArgumentException"
								 reason:@"TMModelKeyFromViewNameTransformer view names must be NSStrings."
							   userInfo:nil] raise];
	if ([key respondsToSelector:@selector(stringValue)])
		// it's an NSNumber
		keyString = [key stringValue];
	else if ([key isKindOfClass:[NSString class]]) keyString = key;
	else
		[[NSException exceptionWithName:@"TMInvalidArgumentException"
								 reason:@"TMModelKeyFromViewNameTransformer model keys must either be NSStrings or NSNumbers."
							   userInfo:nil] raise];
	
	[namesForKeys setObject:name forKey:keyString];
	[keysForNames setObject:keyString forKey:name];
}

- (NSEnumerator *) viewNames {
	return [keysForNames keyEnumerator];
}

- (NSEnumerator *) modelKeys {
	return [namesForKeys keyEnumerator];
}

@end

@implementation TMModelKeyFromViewNameTransformer (Invoked)

+ (Class) transformedValueClass {
	return [NSString class];
}

+ (BOOL) allowsReverseTransformation {
	return YES;
}

- (id) transformedValue:(id)value {	
	if (value == nil) return nil;
	
	NSString *key;
	if ([value respondsToSelector:@selector(stringValue)])
		// if it is an NSNumber
		key = [value stringValue];
	else if ([value isKindOfClass:[NSString class]]) key = value;
	else
		[[NSException exceptionWithName:@"TMInvalidArgumentException"
								 reason:@"TMModelKeyFromViewNameTransformer can only convert NSStrings and NSNumbers."
							   userInfo:nil] raise];
	
	return [namesForKeys objectForKey:key];
}

- (id) reverseTransformedValue:(id)value {
	return [keysForNames objectForKey:value];
}

@end